/*

C++ STL 标准库中提供有 4 种无序关联式容器，本节先讲解 unordered_map 容器。

unordered_map 容器，直译过来就是"无序 map 容器"的意思。所谓“无序”，指的是 unordered_map 容器不会像 map 容器那样对存储的数据进行排序。换句话说，unordered_map 容器和 map 容器仅有一点不同，即 map 容器中存储的数据是有序的，而 unordered_map 容器中是无序的。

对于已经学过 map 容器的读者，可以将 unordered_map 容器等价为无序的 map 容器。

具体来讲，unordered_map 容器和 map 容器一样，以键值对（pair类型）的形式存储数据，存储的各个键值对的键互不相同且不允许被修改。但由于 unordered_map 容器底层采用的是哈希表存储结构，该结构本身不具有对数据的排序功能，所以此容器内部不会自行对存储的键值对进行排序。

C++ 11标准中加入了unordered系列的容器。unordered_map记录元素的hash值，根据hash值判断元素是否相同。map相当于java中的TreeMap，unordered_map相当于HashMap。无论从查找、插入上来说，unordered_map的效率都优于hash_map，更优于map；而空间复杂度方面，hash_map最低，unordered_map次之，map最大。

=================迭代器=========================
begin 　　返回指向容器起始位置的迭代器（iterator）
end 　　 返回指向容器末尾位置的迭代器
cbegin　 返回指向容器起始位置的常迭代器（const_iterator）
cend 　　 返回指向容器末尾位置的常迭代器
=================Capacity================
size 　　 返回有效元素个数
max_size 返回 unordered_map 支持的最大元素个数
empty 判断是否为空
=================元素访问=================
operator[] 　　 访问元素
at 　　 　　　　访问元素
=================元素修改=================
insert 　　插入元素
erase　　 删除元素
swap 　　 交换内容
clear　　 清空内容
emplace 　构造及插入一个元素
emplace_hint 按提示构造及插入一个元素
================操作=========================
find 　　　　　　通过给定主键查找元素,没找到：返回unordered_map::end
count 　　　　　返回匹配给定主键的元素的个数
equal_range 　　返回值匹配给定搜索值的元素组成的范围
================Buckets======================
bucket_count 　　　返回槽（Bucket）数
max_bucket_count 返回最大槽数
bucket_size 　　　 返回槽大小
bucket 　　　　　　返回元素所在槽的序号
load_factor　　　　 返回载入因子，即一个元素槽（Bucket）的最大元素数
max_load_factor 　 返回或设置最大载入因子
rehash　　　　　　 设置槽数
reserve 　　　　　 请求改变容器容量

*/
#include <unordered_map>

#include <iostream>
#include <string>
using std::cout;
using std::endl;

using std::string;

using std::unordered_map;
using std::pair;
using std::make_pair;

void display(unordered_map<string, double> myrecipe,string str)
{
    cout << str << endl;
    for (auto& x: myrecipe)
        cout << x.first << ": " << x.second << endl;
    cout << endl;
}

int main ()
{
    /****************声明2个unordered_map*****************/
    unordered_map<string, double>
    myrecipe, // 创建空的 unordered_map 容器
    mypantry = {{"milk",2.0},{"flour",1.5}}; // 创建 unordered_map 容器的同时，可以完成初始化操作

    // 在创建好 mypantry 容器的基础上，再创建并初始化一个 umap_3 容器
    // 由此，umap_3 容器中就包含有 mypantry 容器中所有的键值对。
    std::unordered_map<string, double> umap_3(mypantry);

    /****************插入*****************/
    pair<string, double> myshopping ("baking powder",0.3);
    myrecipe.insert (myshopping);                        // 复制插入
    myrecipe.insert (make_pair<string, double>("eggs",6.0)); // 移动插入
    myrecipe.insert (mypantry.begin(), mypantry.end());  // 范围插入
    myrecipe.insert ({{"sugar",0.8},{"salt",0.1}});    // 初始化数组插入(可以用二维一次插入多个元素，也可以用一维插入一个元素)
    myrecipe["coffee"] = 10.0;  //数组形式插入


    /****************传参遍历*****************/
    display(myrecipe,"myrecipe contains:");

    /****************查找*****************/
    // 通过常迭代器查找
    //unordered_map<string, double>::const_iterator got = myrecipe.find ("coffee");
    auto got = myrecipe.find ("coffee");

    if ( got == myrecipe.end() )
    {
        cout << "not found";
    }
    else
    {
        cout << "found "<<got->first << " is " << got->second<<"\n\n";
    }

    /****************修改*****************/
    myrecipe.at("coffee") = 9.0;
    myrecipe["milk"] = 3.0;
    display(myrecipe,"After modify myrecipe contains:");


    /****************擦除*****************/
    myrecipe.erase(myrecipe.begin());  //通过位置
    myrecipe.erase("milk");    //通过key
    display(myrecipe,"After erase myrecipe contains:");

    /****************交换*****************/
    myrecipe.swap(mypantry);
    display(myrecipe,"After swap with mypantry, myrecipe contains:");

    /****************清空*****************/
    myrecipe.clear();
    display(myrecipe,"After clear, myrecipe contains:");
    return 0;
}

int test_unordered_map(void)
{
#if 0
    // 在
    std::unordered_map<std::string, std::string> umap
    {
        {"Python", "python"},
        {"Linux", "linux"}
    };
#else
    //
    std::unordered_map<std::string, std::string> umap;
#endif


    //输出 umap 存储键值对的数量
    cout << "umap size = " << umap.size() << endl;
    //使用迭代器输出 umap 容器存储的所有键值对
    for (auto iter = umap.begin(); iter != umap.end(); ++iter) {
        cout << iter->first << " " << iter->second << endl;
    }

    return 0;
}
